package com.devops.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.devops.admin.model.*;
import com.devops.admin.po.DOSClusterPo;
import com.devops.admin.po.DOSK8sIngressPo;
import com.devops.admin.po.DOSProjectPo;
import com.devops.admin.service.*;
import com.devops.admin.util.K8sClientUtil;
import com.devops.admin.vo.*;
import com.devops.constant.DevOpsConstant;
import com.devops.shiro.vm.BaseUserVM;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressList;
import io.fabric8.kubernetes.api.model.networking.v1.IngressSpec;
import io.fabric8.kubernetes.client.KubernetesClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName DOSIngressServiceIMpl
 * @Description TODO
 * @Author heyabo
 * @Date 2022/9/27 16:15
 * @Version 1.0
 **/
@Slf4j
@Service
public class DOSK8sIngressServiceImpl implements DOSK8sIngressService {

    @Autowired
    private DOSProjectService dosProjectService;
    @Autowired
    private DOSClusterService dosClusterService;
    @Autowired
    DOSReleaseService dosReleaseService;
    @Autowired
    DOSClusterNamespaceService dosClusterNamespaceService;

    @Override
    public TableResult<DOSK8sIngressPo> getIngressByUser(DOSK8sIngressVo ingressVo, DOSPageVo pageVo) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        List<DOSK8sIngressPo> dosk8SIngressPos;
        List<DOSClusterPo> clusterPos;
        if (user.getAdminRole()){
            // 如果管理员身份的用户没有选择查询条件则直接返回为空，因为数据太多
            if (ingressVo.getClusterId() == null && ingressVo.getNamespaceId() == null
                    && StrUtil.isEmpty(ingressVo.getIngressName())){
                return null;
            }
            // 管理员查询
            clusterPos = dosClusterService.getClusterAndNamespaceAndClusterInfo(ingressVo);
        }else{
            // 普通用户查询
            List<DOSProjectPo> projects = dosProjectService.getProjectsByUserId(DOSProjectVo.builder().userId(user.getId()).build());
            if (CollectionUtil.isEmpty(projects)){
                return null;
            }
            List<Integer> projectIds = projects.stream().map(DOSProjectPo::getId).collect(Collectors.toList());
            clusterPos = dosClusterService.getClusterAndNamespaceAndClusterInfo(ingressVo, projectIds);
        }
        if (CollectionUtil.isEmpty(clusterPos)){
            return null;
        }
        // 查询远端的ingress
        dosk8SIngressPos = queryIngress(ingressVo, clusterPos);
        // 对查询结果进行分页处理并返回
        return getDosk8sIngressPage(pageVo, dosk8SIngressPos);
    }

    @Override
    public TableResult<DOSK8sIngressPo> getIngress(DOSClusterVo clusterVo, DOSPageVo pageVo) {

        DOSK8sIngressVo ingressVo = DOSK8sIngressVo.builder()
                .clusterId(clusterVo.getId()).build();
        if (clusterVo.getNamespaceId() != null && clusterVo.getNamespaceId() > 0){
            ingressVo.setNamespaceId(clusterVo.getNamespaceId());
        }
        if (StrUtil.isNotEmpty(clusterVo.getIngressName())){
            ingressVo.setIngressName(clusterVo.getIngressName());
        }
        // 查询集群，命名空间，clusterInfo
        List<DOSClusterPo> dosClusterPos = dosClusterService.getClusterAndNamespaceAndClusterInfo(ingressVo);
        if (CollectionUtil.isEmpty(dosClusterPos)){
            return null;
        }
        // 查询ingress
        List<DOSK8sIngressPo> ingressPos = queryIngress(ingressVo, dosClusterPos);
        // 封装查询的ingress为分页数据
        return getDosk8sIngressPage(pageVo,ingressPos);
    }

    @Override
    public List<DOSK8sIngressPo> getReleaseIngress(DOSNamespaceChart namespaceChart) {

        List<DOSK8sIngressPo> dosK8sIngressPos = new ArrayList<>();
        if (namespaceChart.getReleaseType() != null && namespaceChart.getReleaseType().intValue() == DevOpsConstant.ReleaseType.YAML.intValue()){
            // 通过yaml方式部署的查询方式
            Ingress ingress = namespaceChart.getClient()
                    .network().v1().ingresses()
                    .inNamespace(namespaceChart.getNamespace())
                    .withName(namespaceChart.getName()).get();
            dosK8sIngressPos.add(K8sClientUtil.getDOSK8sIngressPo(null, ingress));
        } else {
            // 通过helm方式部署的查询方式
            IngressList ingressList = namespaceChart.getClient()
                    .network().v1().ingresses()
                    .inNamespace(namespaceChart.getNamespace())
                    .withLabel(DevOpsConstant.K8sConfig.POD_LABEL_RELEASE_NAME, namespaceChart.getReleaseName())
                    .withLabel(DevOpsConstant.K8sConfig.POD_LABEL_CHART_NAME, namespaceChart.getChartName()).list();
            dosK8sIngressPos = K8sClientUtil.analysisIngress(ingressList,null,null);
        }

        return dosK8sIngressPos;
    }

    /**
     * @Author heyabo
     * @Description 对ingress查询结果进行分页处理
     * @Date 11:09 2022/9/30
     * @Param [pageVo, dosk8sInressPos]
     * @return com.devops.admin.model.TableResult<com.devops.admin.po.DOSK8sInressPo>
     **/
    private TableResult<DOSK8sIngressPo> getDosk8sIngressPage(DOSPageVo pageVo, List<DOSK8sIngressPo> dosk8SIngressPos) {
        TableResult<DOSK8sIngressPo> tableResult = new TableResult<>();
        List<DOSK8sIngressPo> pageClusters = dosk8SIngressPos.stream().skip((long) (pageVo.getPageNum() - 1) * pageVo.getPageSize())
                .limit(pageVo.getPageSize()).
                collect(Collectors.toList());

        Pagination p = Pagination.builder().pageNum(Long.valueOf(pageVo.getPageNum()))
                .pageSize(Long.valueOf(pageVo.getPageSize())).total((long) dosk8SIngressPos.size()).build();
        tableResult.setList(pageClusters);
        tableResult.setPagination(p);
        return tableResult;
    }

    /**
     * @Author heyabo
     * @Description 查询远端ingress
     * @Date 11:09 2022/9/30
     * @Param [ingressVo, clusterPos]
     * @return java.util.List<com.devops.admin.po.DOSK8sInressPo>
     **/
    private List<DOSK8sIngressPo> queryIngress(DOSK8sIngressVo ingressVo, List<DOSClusterPo> clusterPos) {
        List<DOSK8sIngressPo> dosk8SIngressPos = new ArrayList<>();
        Map<Integer, List<DOSClusterPo>> listMap = clusterPos.stream().collect(Collectors.groupingBy(DOSClusterPo::getId));
        for (Map.Entry<Integer, List<DOSClusterPo>> entry : listMap.entrySet()) {
            DOSClusterPo clusterPo = entry.getValue().get(0);
            KubernetesClient client = K8sClientUtil.getKubernetesClient(clusterPo.getConfigPath(),clusterPo.getConfigContent());
            IngressList list;
            if (ingressVo.getNamespaceId() != null && ingressVo.getNamespaceId() > 0){
                DOSClusterNamespace clusterNamespace = dosClusterNamespaceService.getById(ingressVo.getNamespaceId());
                list = client.network().v1().ingresses().inNamespace(clusterNamespace.getNamespace()).list();
            } else {
                list = client.network().v1().ingresses().list();
            }
            log.debug("查询ingress结果: {}", JSONUtil.toJsonStr(list.getItems().stream().map(Ingress::getSpec).map(IngressSpec::getRules).collect(Collectors.toList())));
            List<DOSK8sIngressPo> ingressPos = K8sClientUtil.analysisIngress(list, clusterPo.getClusterName(), ingressVo.getIngressName());
            if (CollectionUtil.isNotEmpty(ingressPos)) {
                dosk8SIngressPos.addAll(ingressPos);
            }
        }
        return dosk8SIngressPos;
    }
}
